package spotGUI.floatingChatGUI;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Properties;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.Timer;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.text.StyledEditorKit;

import managers.OptionsManager;
import managers.conversationManager.Conversation;
import managers.conversationManager.OnlineConversation;
import managers.conversationManager.services.SendFile;
import managers.messengerManager.MessengerManager;
import net.tomahawk.ExtensionsFilter;
import net.tomahawk.XFileDialog;
import say.swing.JFontChooser;
import utils.PopupUtils;
import utils.StackTracePrinter;
import audio.AudioManager;
import java.util.ResourceBundle;

public class SingleConversationPanel extends JPanel {

	private static final String WORDS_FILE = "kWords.txt";
	private static final String K_TITLE = ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.kTitle");
	private static final String K_MESSAGE = ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.kMessage"); 

	private static final int STOP_WRITING_TIME = 2000;

	private Conversation conv;
	private boolean writing = false;
	private Timer writingTimer;

	private JSplitPane splitPane;
	private JTextPane conversationEditor;
	private JTextPane senderEditor;
	private JScrollPane conversationEditorScrollPane;
	private JScrollPane senderEditorScrollPane;
	private JPanel panel;
	private JLabel label;
	private JLabel label_1;
	private JLabel lblName;
	private JLabel label_2;

	private FloatingChatFrame frame;

	private XFileDialog saveFileDialog;
	private XFileDialog sendFileDialog;
	private JDialog colorDialog;
	private JColorChooser colorChooser;
	private JFontChooser fontChooser;
	private MutableAttributeSet defaultSet;
	
	private EmoticonsChooser chooser;
	private ShortcutsParser parser;

	private Properties chatPanelOptions = OptionsManager.getSharedInstance().getOptionGroup("chatPanel");
	private Properties soundOptions = OptionsManager.getSharedInstance().getOptionGroup("soundPopup");

	
	private ArrayList<String> kWords = new ArrayList<String>();

	private KeyListener writingListener = new KeyAdapter() {

		@Override
		public void keyTyped(KeyEvent arg0) {
			if (writing == false) {
				writing = true;
				writingTimer.restart();
				try {
					conv.sendWritingState(OnlineConversation.WRITING);
				} catch (IOException e) {
					// do nothing
					StackTracePrinter.print(e);
				}
			} else {
				writingTimer.restart();
			}
		}
	};

	private KeyListener kAlertListener = new KeyAdapter() {

		boolean check = false;

		public void keyPressed(KeyEvent e) {

			if (e.getKeyCode() == KeyEvent.VK_K) {
				check = true;
			}


			if (check && e.getKeyCode() == KeyEvent.VK_SPACE) {
				int position = senderEditor.getCaretPosition();
				Document doc = senderEditor.getDocument();
				try {
					String text = doc.getText(0, doc.getLength());

					int start = position;
					do {
						start--;
						if (Character.isWhitespace(text.charAt(start))) {
							start++;
							break;
						}
					} while (start > 0);
					String word = text.substring(start, position);

					if (Collections.binarySearch(kWords, word) < 0) {
						kAlarm();
						doc.remove(start, position-start+1);
					}
				} catch (BadLocationException e1) {
					StackTracePrinter.print(e1);
				}
				check = false;
			}

		}

	};

	private ActionListener btnEmoticonsListener = new ActionListener() {
		public void actionPerformed(ActionEvent arg0) {
			if (chooser.isVisible() == true)
				chooser.setVisible(false);
			else
				chooser.setVisible(true);
		}
	};

	private ActionListener btnColorListener = new ActionListener() {
		public void actionPerformed(ActionEvent arg0) {
			colorChooser.setColor(Integer.parseInt(chatPanelOptions.getProperty("color")));
			colorDialog.setVisible(true);
			senderEditor.requestFocusInWindow();
		}
	};

	private ActionListener btnFontListener = new ActionListener() {
		public void actionPerformed(ActionEvent arg0) {
			int code = fontChooser.showDialog(frame);
			if (code == JFontChooser.OK_OPTION) {
				chatPanelOptions.setProperty("fontName", fontChooser.getSelectedFont().getName());
				chatPanelOptions.setProperty("fontSize", Integer.toString(fontChooser.getSelectedFontSize()));
				chatPanelOptions.setProperty("fontStyle", Integer.toString(fontChooser.getSelectedFontStyle()));
				OptionsManager.getSharedInstance().storeOptionGroup("chatPanel");
				senderEditor.requestFocusInWindow();
				updateEditorFont();
			}
		}
	};


	private ActionListener btnSendListener = new ActionListener() {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			if (senderEditor.getDocument().getLength() == 0)
				return;
			Thread thread = new Thread () {
				public void run() {
					try {
						ByteArrayOutputStream baos = new ByteArrayOutputStream();
						senderEditor.getEditorKit().write(baos, senderEditor.getDocument(), 0, senderEditor.getDocument().getLength());
						senderEditor.setText("");
						byte[] bytes = baos.toByteArray();
						conv.sendMessage(bytes);
						senderEditor.requestFocus();
						updateConversation(bytes, false, Calendar.getInstance().getTime());
					} catch (Exception e) {
						frame.updateStatus(ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.conversationEditor.toolTipText"), FloatingChat.MESSAGE_ERROR_ICON);
						StackTracePrinter.print(e);
					
					}
				}
			};			
			thread.start();
		};
	};

	private ActionListener btnExportConversationListener = new ActionListener() {

		@Override
		public void actionPerformed(ActionEvent arg0) {

			String fileName = saveFileDialog.getSaveFile();
			String directory = saveFileDialog.getDirectory();
			try {
				File f = new File(directory+fileName);
				if (!f.exists()) {
					if (!f.getName().endsWith(".rtf")) {
						f= new File(f.getPath()+".rtf");
					}
					f.createNewFile();
					writeConversation(f);
				} else {
					int ow= JOptionPane.showConfirmDialog(null, ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.2"),
							ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.3"), JOptionPane.YES_NO_OPTION);
					if (ow == JOptionPane.YES_OPTION) {
						writeConversation(f);
					}
				}
			} catch (Exception e) {
				frame.updateStatus(ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.4"), FloatingChat.ERROR_ICON);
				StackTracePrinter.print(e);
			}
		};

	};

	private ActionListener btnSendFileListener = new ActionListener() {

		@Override
		public void actionPerformed(ActionEvent arg0) {

			String fileName = sendFileDialog.getFile();
			String directory = sendFileDialog.getDirectory();
			if (fileName != null) {
				File f = new File(directory+fileName);
				try {
					int id = conv.getUserId();
					new SendFile (MessengerManager.getSharedInstance().getDataManager().getUser(id), f).start();
				} catch (IOException e) {
					StackTracePrinter.print(e);
					frame.getFiletransferManager().getSendFileFeedback().updateLogBar(ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.5"), null);
				}
			}
		}

	};

	private ActionListener btnTrillListener = new ActionListener() {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			try {
				conv.sendWritingState(OnlineConversation.TRILL);
				updateConversation("Hai inviato un trillo!\n", false, Calendar.getInstance().getTime());
				if (soundOptions.getProperty("trill.SOUND").equals("true")) {
					String[] attributes = soundOptions.getProperty("trill.SOUNDPATH").split(",");
					AudioManager.getSharedInstance().play(attributes[0], attributes);
				}
			} catch (IOException e) {
				StackTracePrinter.print(e);
				frame.updateStatus(ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.6"), FloatingChat.ERROR_ICON);
			} catch (Exception e) {
				StackTracePrinter.print(e);
			}
		}
	};

	
	
	public SingleConversationPanel(final FloatingChatFrame frame, EmoticonsChooser chooser, ShortcutsParser parser) {

		this.frame = frame;
		this.chooser = chooser;
		this.parser = parser;

		saveFileDialog = new XFileDialog("Salva");
		Vector<String> extensions = new Vector<String>();
		extensions.addElement("rtf");
		saveFileDialog.addFilters(new ExtensionsFilter("File RTF (Rich Text Format)", extensions));

		sendFileDialog = new XFileDialog("Apri");

		defaultSet = new SimpleAttributeSet();
		defaultSet.addAttribute(StyleConstants.CharacterConstants.Foreground, Color.BLACK);
		defaultSet.addAttribute(StyleConstants.Bold, true);

		writingTimer =  new Timer(STOP_WRITING_TIME, new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				writing = false;
				try {
					conv.sendWritingState(OnlineConversation.STOP_WRITING);
				} catch (IOException e) {
					// do nothing
					StackTracePrinter.print(e);
				}
			}
		});
		writingTimer.setRepeats(false);


		setLayout(new BorderLayout(0, 0));
		splitPane = new JSplitPane();
		splitPane.setOpaque(false);
		splitPane.setMinimumSize(new Dimension(10, 20));
		splitPane.setResizeWeight(0.7);
		splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
		add(splitPane, BorderLayout.CENTER);

		conversationEditor = new JTextPane();
		conversationEditor.setOpaque(false);
		conversationEditor.setToolTipText(ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.conversationEditor.toolTipText")); //$NON-NLS-1$ //$NON-NLS-2$
		conversationEditor.setEditable(false);
		PopupUtils.addPopup(conversationEditor, new EditorPopup(conversationEditor));
		conversationEditor.setContentType("text/rtf");
		conversationEditorScrollPane = new JScrollPane();
		conversationEditorScrollPane.setOpaque(false);
		conversationEditorScrollPane.setMinimumSize(new Dimension(10, 10));
		conversationEditorScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		conversationEditorScrollPane.setViewportView(conversationEditor);
		splitPane.setLeftComponent(conversationEditorScrollPane);

		senderEditor = new JTextPane();
		senderEditor.setToolTipText(ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.senderEditor.toolTipText")); //$NON-NLS-1$ //$NON-NLS-2$
		senderEditor.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		PopupUtils.addPopup(senderEditor, new EditorPopup(senderEditor));
		senderEditor.setContentType("text/rtf");
		senderEditorScrollPane = new JScrollPane();
		senderEditorScrollPane.setToolTipText("");
		senderEditorScrollPane.setOpaque(false);
		senderEditorScrollPane.setMinimumSize(new Dimension(10, 10));
		senderEditorScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		senderEditorScrollPane.setViewportView(senderEditor);
		splitPane.setRightComponent(senderEditorScrollPane);
		senderEditor.setOpaque(false);
		senderEditor.addKeyListener(writingListener);
		senderEditor.addKeyListener(kAlertListener);
		arrangeKeyBindings();

		populateKArrayList();

		label_2 = new JLabel("");
		label_2.setIcon(new ImageIcon(SingleConversationPanel.class.getResource("/images/GUIBackgrounds/writeHere.png")));
		senderEditorScrollPane.setColumnHeaderView(label_2);

		panel = new JPanel();
		add(panel, BorderLayout.NORTH);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{106, 107, 0};
		gbl_panel.rowHeights = new int[]{22, 65, 0};
		gbl_panel.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
		gbl_panel.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE};
		panel.setLayout(gbl_panel);

		label_1 = new JLabel("");
		label_1.setIcon(new ImageIcon(SingleConversationPanel.class.getResource("/images/GUIBackgrounds/chatWith.png")));
		GridBagConstraints gbc_label_1 = new GridBagConstraints();
		gbc_label_1.anchor = GridBagConstraints.WEST;
		gbc_label_1.insets = new Insets(0, 0, 5, 0);
		gbc_label_1.gridx = 1;
		gbc_label_1.gridy = 0;
		panel.add(label_1, gbc_label_1);

		label = new JLabel("");
		label.setIcon(new ImageIcon(SingleConversationPanel.class.getResource("/images/Icons/128x128px/comments.png")));
		GridBagConstraints gbc_label = new GridBagConstraints();
		gbc_label.gridheight = 2;
		gbc_label.insets = new Insets(0, 0, 0, 5);
		gbc_label.gridx = 0;
		gbc_label.gridy = 0;
		panel.add(label, gbc_label);

		lblName = new JLabel("nome utente");
		GridBagConstraints gbc_lblName = new GridBagConstraints();
		gbc_lblName.anchor = GridBagConstraints.NORTH;
		gbc_lblName.gridx = 1;
		gbc_lblName.gridy = 1;
		panel.add(lblName, gbc_lblName);

		fontChooser = createFontChooser();
		fontChooser.setSelectedFont(new Font(chatPanelOptions.getProperty("fontName"), new Integer(chatPanelOptions.getProperty("fontStyle")), 
				new Integer(chatPanelOptions.getProperty("fontSize"))));
		updateEditorFont();
		colorDialog = createColorChooser(frame);
		updateEditorColor();

		frame.setFeature("emoticons", btnEmoticonsListener);
		frame.setFeature("font", btnFontListener);
		frame.setFeature("color", btnColorListener);
		frame.setFeature("send", btnSendListener);
		frame.setFeature("trill", btnTrillListener);
		frame.setFeature("exportConversation", btnExportConversationListener);
		frame.setFeature("fileTransfer", btnSendFileListener);
	}


	private void arrangeKeyBindings() {
		ActionMap map = senderEditor.getActionMap();
		InputMap iMap = senderEditor.getInputMap();
		
		iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK), iMap.get(KeyStroke.getKeyStroke("ENTER")));
		map.put("sendMessage", new AbstractAction() {
			@Override
			public void actionPerformed(ActionEvent e) {
				btnSendListener.actionPerformed(new ActionEvent(senderEditor, 0, ""));
			};
		});
		iMap.put(KeyStroke.getKeyStroke("ENTER"), "sendMessage");
	}


	public void setConversation (Conversation conv) {
		this.conv = conv;
	}

	public Conversation getConversation() {
		return conv;
	}


	private Properties options = OptionsManager.getSharedInstance().getOptionGroup("messenger");

	public void updateConversation (Object message, boolean incomingMessage, Date date) throws IOException, BadLocationException {
		StyledDocument doc = (StyledDocument) conversationEditor.getDocument();

		if (incomingMessage)
			doc.insertString(doc.getLength(), lblName.getText(), defaultSet);
		else
			doc.insertString(doc.getLength(), ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.c1"), defaultSet);
		
		if (options.getProperty("viewTimeOnMessages").equals("true"))
			doc.insertString(doc.getLength(), ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.c2")+ DateFormat.getTimeInstance(DateFormat.SHORT).format(date), defaultSet);
		
		if (options.getProperty("viewDateOnMessages").equals("true"))
			doc.insertString(doc.getLength(), ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.c3")+DateFormat.getDateInstance(DateFormat.LONG).format(date), defaultSet);
		
		doc.insertString(doc.getLength(), " :\n", defaultSet);

		if (message instanceof byte[])
			conversationEditor.getEditorKit().read(new ByteArrayInputStream((byte[]) message), conversationEditor.getDocument(), conversationEditor.getDocument().getLength());
		else
			doc.insertString(doc.getLength(), (String) message, defaultSet);

		//saving on file
		if (options.getProperty("storeConversations").equals("true")) {
			try {
				File f = new File (options.getProperty("conversationFolder")+"/"+frame.getReceiverName()+".rtf");
				if (!f.exists())
					f.createNewFile();
				writeConversation(f);
			} catch (IOException e) {
				frame.updateStatus(ResourceBundle.getBundle("spotGUI.floatingChatGUI.messages").getString("SingleConversationPanel.7"),
						FloatingChat.ERROR_ICON);
			}
		}


		try {
			parser.parse(conversationEditor);
		} catch (BadLocationException e) {
			//do nothing
			StackTracePrinter.print(e);
		}
		conversationEditorScrollPane.getVerticalScrollBar().setValue(Integer.MAX_VALUE);
	}

	public JTextPane getSenderEditor() {
		return senderEditor;
	}
	public JTextPane getConversationEditor() {
		return conversationEditor;
	}
	public JLabel getLblName() {
		return lblName;
	}




	private JDialog createColorChooser(FloatingChatFrame parent) {

		colorChooser = new JColorChooser();
		colorChooser.setPreviewPanel(new JPanel());
		colorChooser.setColor(new Color(Integer.parseInt(chatPanelOptions.getProperty("color"))));

		ActionListener okListener = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				chatPanelOptions.setProperty("color", Integer.toString(colorChooser.getColor().getRGB()));
				OptionsManager.getSharedInstance().storeOptionGroup("chatPanel");
				updateEditorColor();
			}
		};

		return JColorChooser.createDialog(parent, "Scegli colore", false, colorChooser, okListener, null);
	}

	private JFontChooser createFontChooser() {
		JFontChooser temp = new JFontChooser();
		return temp;

	}

	private void updateEditorFont() {

		StyledDocument doc = (StyledDocument) senderEditor.getDocument();
		SimpleAttributeSet attributes = new SimpleAttributeSet();

		switch (fontChooser.getSelectedFontStyle()) {
		case 0:
			attributes.addAttribute(StyleConstants.Bold, false);
			attributes.addAttribute(StyleConstants.Italic, false);
			break;
		case 1:
			attributes.addAttribute(StyleConstants.Bold, true);
			break;
		case 2: 
			attributes.addAttribute(StyleConstants.Italic, true);
			break;
		case 3:
			attributes.addAttribute(StyleConstants.Bold, true);
			attributes.addAttribute(StyleConstants.Italic, true);
		}
		attributes.addAttribute(StyleConstants.Size, fontChooser.getSelectedFontSize());
		attributes.addAttribute(StyleConstants.FontFamily, fontChooser.getSelectedFontFamily());

		int start = senderEditor.getSelectionStart();
		int end = senderEditor.getSelectionEnd();
		doc.setCharacterAttributes(start, end-start, attributes, false);
		senderEditor.setCharacterAttributes(attributes, false);
	}

	private void updateEditorColor () {
		new StyledEditorKit.ForegroundAction("Color", colorChooser.getColor()).actionPerformed(new ActionEvent(senderEditor, 0, ""));
	}

	private void writeConversation (File file) throws IOException, BadLocationException {
		FileOutputStream bw = new FileOutputStream(file);
		senderEditor.getEditorKit().write(bw, conversationEditor.getDocument(), 0, conversationEditor.getDocument().getLength());
		bw.close();
	}

	@Override
	public void setEnabled(boolean enabled) {
		senderEditor.setEnabled(enabled);
	}

	private void kAlarm() {
		try {
			AudioManager.getSharedInstance().play("kAlert.soundPath");
		} catch (Exception e) {
			//do nothing
			StackTracePrinter.print(e);
		}
		JOptionPane.showConfirmDialog(this, K_MESSAGE, K_TITLE, JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
	}

	private void populateKArrayList () {
		try {
			BufferedReader br = new BufferedReader(new FileReader(new File (WORDS_FILE)));
			String line;
			while ((line=br.readLine()) != null) {
				kWords.add(line);
			}
			br.close();
		} catch (FileNotFoundException e) {
			StackTracePrinter.print(e);
		} catch (IOException e) {
			StackTracePrinter.print(e);
		}

	}




}
